Q: How do I calculate the video frame rate of an MPEG-1 or MPEG-2 movie? A: The easiest way to get this information is with the new MediaGetPublicInfo function, which was introduced in QuickTime 5 (see MediaHandlers.h). Simply pass the selector kMHInfoEncodedFrameRate . Note also for MPEG media there is a bug (r. 3236091) in QuickTime 6 which requires you to first task the movie using the MoviesTask function before calling MediaGetPublicInfo to get the frame rate information. For other media types (including the new MPEG-4 format) you must continue to compute the frame rate using the "old" method where the frames are counted using GetMediaSampleCount (or GetMovieNextInterestingTime ), and the media duration and time scale are used along with this value to derive the frame rate. Listing 1 below shows how this is done:
Listing 1. Listing 1 - Calculating the video frame rate of an MPEG movie. | #include <QuickTime/QuickTime.h>
#define kCharacteristicHasVideoFrameRate FOUR_CHAR_CODE('vfrr')
#define kCharacteristicIsAnMpegTrack FOUR_CHAR_CODE('mpeg')
#define BailOnMoviesErr(err) {if (err) goto bail; }
OSErr GetMovieFPS(Movie theMovie, short *fps)
{
MediaHandler mpegMediaHandler = nil;
Track theTrack = nil;
Media myMedia = nil;
OSErr err = noErr;
Boolean isMpeg = false;
/* initialize frame rate value */
*fps = 0;
if (theMovie == nil) goto bail;
/* get the video track */
theTrack = GetMovieIndTrackType(theMovie,
1,
kCharacteristicHasVideoFrameRate,
movieTrackCharacteristic);
err = GetMoviesError();
BailOnMoviesErr(err != noErr);
/* get the track media */
myMedia = GetTrackMedia(theTrack);
err = GetMoviesError();
BailOnMoviesErr(err != noErr);
/* get a reference to the media handler component */
mpegMediaHandler = GetMediaHandler(myMedia);
err = GetMoviesError();
BailOnMoviesErr(err != noErr);
/* is this the mpeg media handler? */
err = MediaHasCharacteristic(mpegMediaHandler,
kCharacteristicIsAnMpegTrack,
&isMpeg);
if ((err == noErr) && isMpeg)
{
MHInfoEncodedFrameRateRecord encodedFrameRate;
Size encodedFrameRateSize = sizeof(encodedFrameRate);
/* due to a bug in QuickTime, we must task the movie
first before obtaining our frame rate value */
MoviesTask( theMovie, 0 );
/* get the static frame rate */
err = MediaGetPublicInfo(mpegMediaHandler,
kMHInfoEncodedFrameRate,
&encodedFrameRate,
&encodedFrameRateSize);
if (err == noErr)
{
Fixed staticFrameRate = 0;
staticFrameRate = encodedFrameRate.encodedFrameRate;
/* we'll round this value for simplicity - you could
parse the value to also obtain the fractional
portion as well. */
*fps = FixRound(staticFrameRate);
}
}
else /* were dealing with non-MPEG media, so use the "old" method */
{
long sampleCount = 0;
/* get the number of samples in the media */
sampleCount = GetMediaSampleCount(myMedia);
err = GetMoviesError();
BailOnMoviesErr(err != noErr);
if (sampleCount)
{
TimeValue duration;
TimeValue timeScale;
Fixed staticFrameRate = 0;
double frameRate;
/* find the media duration */
duration = GetMediaDuration(myMedia);
err = GetMoviesError();
BailOnMoviesErr(err != noErr);
/* get the media time scale */
timeScale = GetMediaTimeScale(myMedia);
err = GetMoviesError();
BailOnMoviesErr(err != noErr);
/* calculate the frame rate:
frame rate = (sample count * media time scale) / media duration
*/
frameRate = sampleCount*(double)timeScale/(double)duration;
staticFrameRate = X2Fix(frameRate);
/* we'll round this value for simplicity - you could
parse the value to also obtain the fractional
portion as well. */
*fps = FixRound(staticFrameRate);
}
}
bail:
return err;
}
|
Alternately, you could count the MPEG video frames using GetMovieNextInterestingTime as described in QTMTB 54 , then use the media duration and time scale values to compute the frame rate. The code snippet in Listing 2 below demonstrates this technique:
Listing 2. Listing 2 - Calculating the frame rate using GetMovieNextInterestingTime. | #include <QuickTime/QuickTime.h>
long GetFrameCount (Movie theMovie)
{
long frameCount = 0;
TimeValue curMovieTime;
if (theMovie == NULL)
goto bail;
// due to a bug in QuickTime 6 we
// must task the movie first
MoviesTask( theMovie, 0 );
curMovieTime = 0;
while( curMovieTime >= 0 )
{
GetMovieNextInterestingTime(
theMovie,
nextTimeStep,
0, NULL,
curMovieTime,
fixed1,
&curMovieTime,
NULL );
frameCount++;
}
frameCount--; // there's an extra time step at the end of the movie
bail:
return(frameCount);
}
OSErr GetMovieFPS(Movie theMovie, TimeValue *fps)
{
OSErr err = noErr;
TimeValue duration=0,
timeScale=0,
movieDurationInSeconds;
/* initialize fps value */
*fps = 0;
/* get movie duration */
duration = GetMovieDuration(theMovie);
err = GetMoviesError();
BailOnMoviesErr(err != noErr);
/* get movie time scale */
timeScale = GetMovieTimeScale(theMovie);
err = GetMoviesError();
BailOnMoviesErr(err != noErr);
/* get movie length in seconds */
movieDurationInSeconds = duration / timeScale;
/* calculate frame rate */
*fps = GetFrameCount (theMovie) / movieDurationInSeconds;
bail:
return(err) ;
}
|
[Jun 02, 2003]
|